home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / dev / lang / sofa.lha / sofa / smalleiffel / lib_std / basic_directory.e < prev    next >
Text File  |  2000-03-25  |  26KB  |  718 lines

  1. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  2. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  3. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  4. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  5. -- this header is kept unaltered, and a notification of the changes is added.
  6. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  7. -- another product.
  8. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  9. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  10. --                       http://SmallEiffel.loria.fr
  11. --
  12. expanded class BASIC_DIRECTORY
  13. --
  14. -- NOTE: THIS IS AN ALPHA VERSION. THIS CLASS IS NOT STABLE AT ALL AND 
  15. -- MIGHT EVEN CHANGE COMPLETELY IN THE NEXT RELEASE !
  16. -- 
  17. -- Very low-level basic tools for file-system directory handling and file 
  18. -- path manipulation. This class is intended to be platform independant as 
  19. -- much as possible. In order to remove from the client side the burden of 
  20. -- file path computation, this class tries to compute automatically the 
  21. -- system file notation using argument(s) of some of the very first call(s). 
  22. -- As soon as the system notation has been properly detected, the result is 
  23. -- internally memorized for all objects of type BASIC_DIRECTORY in a common 
  24. -- private buffer. Besides the low-level nature of operations one can found 
  25. -- in this class, all file path manipulations are done in a smart way 
  26. -- (except when the system file path notation has not been detected 
  27. -- automatically, which is quite uncommon). As an example, even if the 
  28. -- directory separator is internally detected, this information is 
  29. -- _intentionaly_ kept private to avoid low-level manipulation from the 
  30. -- client side. Finally, this class is expanded in order to avoid as much as 
  31. -- possible memory allocations.
  32. --
  33. -- Also consider hight level facade class DIRECTORY if you don't want 
  34. -- to deal directly with low level directory streams.
  35. --
  36.    
  37. feature {NONE}
  38.    
  39.    directory_stream: POINTER;
  40.          -- This pointer memorize the current directory stream being
  41.          -- scanned (used to compute `is_connected').
  42.  
  43.    current_entry: POINTER;
  44.          -- When `is_connected', memorize the current entry in the 
  45.          -- current  `directory_stream'.
  46.  
  47. feature -- State of `Current' basic directory stream :
  48.    
  49.    is_connected: BOOLEAN is
  50.          -- Is `Current' connected to some directory stream ?
  51.       do
  52.          Result := directory_stream.is_not_null;
  53.       end;
  54.    
  55.    end_of_input: BOOLEAN is
  56.          -- Is end of input reached ?
  57.       require
  58.          is_connected
  59.       do
  60.          Result := current_entry.is_null;
  61.       end;
  62.    
  63. feature -- Connect and disconnect :
  64.    
  65.    connect_to(directory_path: STRING) is
  66.          -- Try to connect `Current' to some existing `directory_path'. After 
  67.          -- this call, the client is supposed to use `is_connected' to check 
  68.          -- that the stream is ready to be used.
  69.       require
  70.          not is_connected;
  71.          not directory_path.is_empty;
  72.          common_buffer_protection: last_entry /= directory_path
  73.       local
  74.          path_pointer: POINTER;
  75.       do
  76.          path_pointer := directory_path.to_external;
  77.          directory_stream := basic_directory_open(path_pointer);
  78.          current_entry := directory_stream;
  79.          last_entry.clear;
  80.       ensure
  81.          is_connected implies not end_of_input
  82.       end;
  83.    
  84.    connect_with(some_path: STRING) is
  85.          -- Try to connect `Current' to some directory using `some_path' which
  86.          -- may  be either an existing directory path or some arbitrary 
  87.          -- file path name. When `some_path' is the path of some readable 
  88.          -- existing directory, this directory is opened and the effect of 
  89.          -- `connect_with' is equivalent to `connect_to'. When `some_path' is not an 
  90.          -- existing readable directory path, `connect_with' tries to open the 
  91.          -- directory which may contains `some_path' viewed as a file path 
  92.          -- name. After this call, the client is supposed to use `is_connected' 
  93.          -- to check that the stream is ready to be used and the `last_entry' 
  94.          -- buffer to know about the corresponding opened directory path. 
  95.          -- Whatever the result, `some_path' is left unchanged.
  96.       require
  97.          not is_connected;
  98.          not some_path.is_empty;
  99.          common_buffer_protection: last_entry /= some_path
  100.       local
  101.          p: POINTER;
  102.       do
  103.          connect_to(some_path);
  104.          if is_connected then
  105.             last_entry.copy(some_path);
  106.          else
  107.             compute_parent_directory_of(some_path);
  108.             if last_entry.count > 0 then
  109.                p := last_entry.to_external;
  110.                directory_stream := basic_directory_open(p);
  111.                current_entry := directory_stream;
  112.                if directory_stream.is_null then
  113.                   last_entry.clear;
  114.                end;
  115.             else
  116.                last_entry.clear;
  117.             end;
  118.          end;
  119.       ensure
  120.          is_connected implies not end_of_input
  121.       end;
  122.    
  123.    connect_to_current_working_directory is
  124.          -- Try to connect `Current' to the current working directory.
  125.          -- After this call, the client is supposed to use `is_connected' 
  126.          -- to check that the stream is ready to be used and the `last_entry' 
  127.          -- buffer to know about the name of the current working directory.
  128.       require
  129.          not is_connected
  130.       local
  131.          path: POINTER;
  132.       do
  133.          path := basic_directory_current_working_directory;
  134.          if path.is_not_null then
  135.             last_entry.from_external_copy(path);
  136.             directory_stream := basic_directory_open(path);
  137.             current_entry := directory_stream;
  138.             if directory_stream.is_null then
  139.                last_entry.clear;
  140.             end;
  141.          else
  142.             last_entry.clear;
  143.          end;
  144.       ensure
  145.          is_connected implies not end_of_input
  146.       end;
  147.    
  148.    disconnect is
  149.          -- Do not forget to call this feature when you have finished 
  150.          -- with some previously opened directory stream.
  151.       require
  152.          is_connected
  153.       local
  154.          null: POINTER;
  155.       do
  156.          if basic_directory_close(directory_stream) then
  157.             directory_stream := null;
  158.             current_entry := null;
  159.          end;
  160.       ensure
  161.          not is_connected
  162.       end;
  163.  
  164. feature -- Scanning :
  165.  
  166.    last_entry: STRING is
  167.          -- Unique global buffer (once object) to get the last information 
  168.          -- computed by many routines of this class: `read_entry', `connect_with'
  169.          -- `connect_to_current_working_directory', `compute_parent_directory_of', ...
  170.       once
  171.          !!Result.make(256);
  172.       end;
  173.    
  174.    read_entry is
  175.          -- Read the next entry name and update `last_entry' and `end_of_input'
  176.          -- accordingly.
  177.       require
  178.          is_connected;
  179.          not end_of_input
  180.       local
  181.          name: POINTER;
  182.       do
  183.          current_entry := basic_directory_read_entry(directory_stream);
  184.          if current_entry.is_not_null then
  185.             name := basic_directory_get_entry_name(current_entry);
  186.             last_entry.from_external_copy(name);
  187.          end;
  188.       end;
  189.  
  190. feature -- File path handling tools :
  191.    
  192.    compute_parent_directory_of(some_path: STRING) is
  193.          -- Using `some_path' (which may be either a file path or a directory 
  194.          -- path) tries to compute in the `last_entry' buffer the parent 
  195.          -- directory of `some_path'. When `some_path' is a path with no parent 
  196.          -- directory, the `last_entry' buffer `is_empty' after this call. This 
  197.          -- operation does not perform any disk access.
  198.       require
  199.          not some_path.is_empty;
  200.          common_buffer_protection: last_entry /= some_path
  201.       do
  202.          last_entry.copy(some_path);
  203.          if unix_like_notation then
  204.             from
  205.                if last_entry.count > 0 then
  206.                   last_entry.remove_last(1);
  207.                end;
  208.             until
  209.                last_entry.is_empty or else last_entry.last = '/'
  210.             loop
  211.                last_entry.remove_last(1);
  212.             end;
  213.      elseif windows_like_notation then
  214.             from
  215.                if last_entry.count > 0 then
  216.                   last_entry.remove_last(1);
  217.                end;
  218.             until
  219.                last_entry.is_empty or else last_entry.last = '\'
  220.             loop
  221.                last_entry.remove_last(1);
  222.             end;
  223.          elseif amiga_like_notation then
  224.             from
  225.                if last_entry.last /= ':' then
  226.                   last_entry.remove_last(1);
  227.                end;
  228.             until
  229.                last_entry.is_empty or else
  230.                last_entry.last = '/' or else
  231.                last_entry.last = ':'
  232.             loop
  233.                last_entry.remove_last(1);
  234.             end;
  235.          elseif macintosh_like_notation then
  236.             from
  237.                if last_entry.last = ':' then
  238.                   last_entry.remove_last(1);
  239.                end;
  240.             until
  241.                last_entry.is_empty or else last_entry.last = ':'
  242.             loop
  243.                last_entry.remove_last(1);
  244.             end;
  245.          elseif vms_like_notation then
  246.             if last_entry.last = ']' then
  247.                from
  248.                   last_entry.remove_last(1);
  249.                until
  250.                   last_entry.is_empty or else 
  251.                   last_entry.last = '.' or else
  252.                   last_entry.last = '['
  253.                loop
  254.                   last_entry.remove_last(1);
  255.                end;
  256.                if last_entry.count > 0 then
  257.                   inspect
  258.                      last_entry.last
  259.                   when '.' then
  260.                      last_entry.remove_last(1);
  261.                      last_entry.extend(']');
  262.                   when '[' then
  263.                      if some_path.count > 2 then
  264.                         last_entry.extend(']');
  265.                      else
  266.                         last_entry.clear;
  267.                      end;
  268.                   end;
  269.                end;
  270.             else
  271.                from
  272.                   last_entry.remove_last(1);
  273.                until
  274.                   last_entry.is_empty or else 
  275.                   last_entry.last = '.' or else 
  276.                   last_entry.last = ']'
  277.                loop
  278.                   last_entry.remove_last(1);
  279.                end;
  280.                if last_entry.count > 0 then
  281.                   last_entry.remove_last(1);
  282.                   last_entry.extend(']');
  283.                end;
  284.             end;
  285.          elseif system_notation_detected then
  286.             last_entry.clear;
  287.          else 
  288.             try_to_compute_notation(some_path);
  289.             if system_notation_detected then
  290.                compute_parent_directory_of(some_path);
  291.             else
  292.                last_entry.clear;
  293.             end;
  294.          end;
  295.       end;
  296.    
  297.    compute_subdirectory_with(parent_path, entry_name: STRING) is
  298.          -- Try to compute in the `last_entry' buffer the new subdirectory 
  299.          -- path obtained when trying to concatenate smartly `parent_path' 
  300.          -- whith some `entry_name'. When this fails the `last_entry' buffer `is_empty' 
  301.          -- after this call. This operation does not perform any disk access.
  302.          -- Whatever the result, `parent_path' and  `entry_name' are left unchanged.
  303.       require
  304.          not parent_path.is_empty;
  305.          not entry_name.is_empty;
  306.          common_buffer_protection1: last_entry /= parent_path;
  307.          common_buffer_protection2: last_entry /= entry_name
  308.       do
  309.          last_entry.copy(parent_path);
  310.          if unix_like_notation then
  311.             if (".").is_equal(entry_name) then
  312.                -- Because you would get the same directory as `parent_path' and 
  313.                -- not a new subdirectory as explained before.
  314.                last_entry.clear;
  315.             elseif ("..").is_equal(entry_name) then
  316.                -- Because you would not get a subdirectory of `parent_path'.
  317.                last_entry.clear;
  318.             else
  319.                last_entry.extend_unless('/');
  320.                if entry_name.first = '/' then
  321.                   last_entry.remove_last(1);
  322.                end;
  323.                last_entry.append(entry_name);
  324.                last_entry.extend_unless('/');
  325.             end;
  326.          elseif windows_like_notation then
  327.             if (".").is_equal(entry_name) then
  328.                -- Because you would get the same directory as `parent_path' and 
  329.                -- not a new subdirectory as explained before.
  330.                last_entry.clear;
  331.             elseif ("..").is_equal(entry_name) then
  332.                -- Because you would not get a subdirectory of `parent_path'.
  333.                last_entry.clear;
  334.             else
  335.                last_entry.extend_unless('\');
  336.                if entry_name.first = '\' then
  337.                   last_entry.remove_last(1);
  338.                end;
  339.                last_entry.append(entry_name);
  340.                last_entry.extend_unless('\');
  341.             end;
  342.          elseif amiga_like_notation then
  343.             inspect 
  344.                last_entry.last
  345.             when '/' then
  346.                if entry_name.first = '/' then
  347.                   last_entry.remove_last(1);
  348.                end;
  349.             when ':' then
  350.             else
  351.                if entry_name.first /= '/' then
  352.                   last_entry.add_last('/');
  353.                end;
  354.             end;
  355.             last_entry.append(entry_name);
  356.             last_entry.extend_unless('/');
  357.          elseif macintosh_like_notation then
  358.             last_entry.extend_unless(':');
  359.             if entry_name.first = ':' then
  360.                last_entry.remove_last(1);
  361.             end;
  362.             last_entry.append(entry_name);
  363.             last_entry.extend_unless(':');
  364.          elseif vms_like_notation then
  365.             if ("[]").is_equal(entry_name) then
  366.                -- Because you would get the same directory as `parent_path' and 
  367.                -- not a new subdirectory as explained before.
  368.                last_entry.clear;
  369.             elseif ("[-]").is_equal(entry_name) then
  370.                -- Because you would not get a subdirectory of `parent_path'.
  371.                last_entry.clear;
  372.             else
  373.                inspect
  374.                   last_entry.last
  375.                when ']' then
  376.                   last_entry.remove_last(1);
  377.                   last_entry.extend('.');
  378.                when '.' then
  379.                else
  380.                   last_entry.extend('.');
  381.                end;
  382.                last_entry.append(entry_name);
  383.                inspect
  384.                   last_entry.last
  385.                when ']' then
  386.                when '.' then
  387.                   last_entry.remove_last(1);
  388.                   last_entry.extend(']');
  389.                else
  390.                   last_entry.extend(']');
  391.                end;
  392.             end;
  393.          elseif system_notation_detected then
  394.             last_entry.clear;
  395.          else 
  396.             try_to_compute_notation(parent_path);
  397.             if system_notation_detected then
  398.                compute_subdirectory_with(parent_path,entry_name);
  399.             else
  400.                last_entry.clear;
  401.             end;
  402.          end;
  403.       end;
  404.    
  405.    compute_file_path_with(parent_path, file_name: STRING) is
  406.          -- Try to compute in the `last_entry' buffer the new file path obtained 
  407.          -- when trying to concatenate smartly `parent_path' whith some 
  408.          -- `file_name'. When this fails the `last_entry' buffer `is_empty' after 
  409.          -- this call. This operation does not perform any disk access.
  410.          -- Whatever the result, `parent_path' and `file_name' are left unchanged.
  411.       require
  412.          not parent_path.is_empty;
  413.          not file_name.is_empty;
  414.          common_buffer_protection1: last_entry /= parent_path;
  415.          common_buffer_protection2: last_entry /= file_name
  416.       do
  417.          last_entry.copy(parent_path);
  418.          if unix_like_notation then
  419.             last_entry.extend_unless('/');
  420.             if file_name.first = '/' then
  421.                last_entry.remove_last(1);
  422.             end;
  423.             last_entry.append(file_name);
  424.          elseif windows_like_notation then
  425.             last_entry.extend_unless('\');
  426.             if file_name.first = '\' then
  427.                last_entry.remove_last(1);
  428.             end;
  429.             last_entry.append(file_name);
  430.          elseif amiga_like_notation then
  431.             inspect
  432.                last_entry.last
  433.             when ':' then
  434.             when '/' then
  435.                if file_name.first = '/' then
  436.                   last_entry.remove_last(1);
  437.                end;
  438.             else
  439.                if file_name.first /= '/' then
  440.                   last_entry.extend('/');
  441.                end;
  442.             end;
  443.             last_entry.append(file_name);
  444.          elseif macintosh_like_notation then
  445.             last_entry.extend_unless(':');
  446.             if file_name.first = ':' then
  447.                last_entry.remove_last(1);
  448.             end;
  449.             last_entry.append(file_name);
  450.          elseif vms_like_notation then
  451.             inspect
  452.                last_entry.last
  453.             when ']' then
  454.             when '.' then
  455.                last_entry.remove_last(1);
  456.                last_entry.extend(']');
  457.             else
  458.                last_entry.extend(']');
  459.             end;
  460.             if file_name.first = ']' then
  461.                last_entry.remove_last(1);
  462.             end;
  463.             last_entry.append(file_name);
  464.          elseif system_notation_detected then
  465.             last_entry.clear;
  466.          else 
  467.             try_to_compute_notation(parent_path);
  468.             if system_notation_detected then
  469.                compute_file_path_with(parent_path,file_name);
  470.             else
  471.                last_entry.clear;
  472.             end;
  473.          end;
  474.       end;
  475.  
  476.    change_current_working_directory(directory_path: STRING) is
  477.          -- Try to change the current working directory using some 
  478.          -- `directory_path'. When the operation is possible, the `last_entry' buffer 
  479.          -- is updated with the new current working directory path, 
  480.          -- otherwise, when the modification is not possible the `last_entry' 
  481.          -- buffer `is_empty' after this call. Whatever the result, 
  482.          -- `directory_path' is left unchanged.
  483.       require
  484.          not is_connected;
  485.          common_buffer_protection1: last_entry /= directory_path
  486.       local
  487.          p: POINTER;
  488.       do
  489.          p := directory_path.to_external;
  490.          if basic_directory_chdir(p) then
  491.             connect_to_current_working_directory;
  492.             if is_connected then
  493.                disconnect;
  494.                check not last_entry.is_empty end;
  495.             else
  496.                last_entry.clear;
  497.             end;
  498.          else
  499.             last_entry.clear;
  500.          end;
  501.       ensure
  502.          not is_connected
  503.       end;
  504.          
  505. feature -- Disk modification :
  506.  
  507.    create_new_directory(directory_path: STRING): BOOLEAN is
  508.          -- Try to create a new directory using the `directory_path' name.
  509.          -- Returns true on success.
  510.       require
  511.          not is_connected
  512.       local
  513.          p: POINTER;
  514.       do
  515.          p := directory_path.to_external;
  516.          Result := basic_directory_mkdir(p);
  517.       ensure
  518.          not is_connected
  519.       end;
  520.    
  521.    remove_directory(directory_path: STRING): BOOLEAN is
  522.          -- Try to remove directory `directory_path' which must be empty.
  523.          -- Returns true on success.
  524.       require
  525.          not is_connected
  526.       local
  527.          p: POINTER;
  528.       do
  529.          p := directory_path.to_external;
  530.          Result := basic_directory_rmdir(p);
  531.       ensure
  532.          not is_connected
  533.       end;
  534.  
  535.    remove_files_of(directory_path: STRING) is
  536.          -- Try to remove all files (not subdirectories) of directory 
  537.          -- specified by `directory_path'.
  538.       require
  539.          not is_connected
  540.       do
  541.          connect_to(directory_path);
  542.          if is_connected then
  543.             from
  544.                read_entry;
  545.             until
  546.                end_of_input
  547.             loop
  548.                tmp_path.copy(last_entry);
  549.                compute_file_path_with(directory_path,tmp_path);
  550.                tmp_path.copy(last_entry);
  551.                remove_file(tmp_path);
  552.                read_entry;
  553.             end;
  554.             disconnect;
  555.          end;
  556.       ensure
  557.          not is_connected
  558.       end;
  559.  
  560. feature {NONE} 
  561.  
  562.    notation: STRING is "?";
  563.          -- Unique common buffer to memorize the system path name 
  564.          -- notation.
  565.  
  566.    system_notation_detected: BOOLEAN is
  567.       do
  568.          Result := notation.first /= '?';
  569.       end;
  570.          
  571.    unix_like_notation: BOOLEAN is
  572.       do
  573.          Result := notation.first = 'U';
  574.       end;
  575.  
  576.    windows_like_notation: BOOLEAN is
  577.       do
  578.          Result := notation.first = 'W';
  579.       end;
  580.  
  581.    amiga_like_notation: BOOLEAN is
  582.          -- The Amiga file path notation looks like:
  583.          --   DEV:directory1/directory2/filename
  584.       do
  585.          Result := notation.first = 'A';
  586.       end;
  587.  
  588.    macintosh_like_notation: BOOLEAN is
  589.          -- The Macintosh file path notation looks like:
  590.          --   :directory1:directory2:filename
  591.       do
  592.          Result := notation.first = 'M';
  593.       end;
  594.  
  595.    vms_like_notation: BOOLEAN is
  596.          -- The VMS file path notation looks like:
  597.          --    [directory1.directory2.directory3]filename
  598.          -- The current working directory notation is:
  599.          --    []
  600.          -- The equivalent of Unix .. is :
  601.          --    [-]
  602.          -- The equivalent of Unix ../.. is :
  603.          --    [-.-]
  604.          --
  605.       do
  606.          Result := notation.first = 'V';
  607.       end;
  608.  
  609.    try_to_compute_notation(some_path: STRING) is
  610.       require
  611.          not system_notation_detected
  612.       do
  613.          if file_exists(some_path) then
  614.             if some_path.has('/') then
  615.                notation.put('U',1);
  616.             elseif some_path.has('\') then
  617.                notation.put('W',1);
  618.             elseif some_path.has(':') then
  619.                notation.put('M',1);
  620.             elseif some_path.has('[') then
  621.                notation.put('V',1);
  622.             else
  623.                last_attempt_to_compute_notation;
  624.             end;
  625.          else
  626.             last_attempt_to_compute_notation;
  627.          end;
  628.       end;
  629.    
  630.    last_attempt_to_compute_notation is
  631.       require
  632.          not system_notation_detected
  633.       do
  634.          if file_exists("s:startup-sequence") then
  635.             notation.put('A',1);
  636.          elseif file_exists("/bin/ls") then
  637.             notation.put('U',1);
  638.          elseif file_exists("C:\AUTOEXEC.BAT") then
  639.             notation.put('W',1);
  640.          end;
  641.       end;
  642.  
  643.    tmp_path: STRING is
  644.       once
  645.          !!Result.make(256);
  646.       end;
  647.  
  648. feature {NONE} 
  649.    -- Following functions external "SmallEiffel" functions (only 
  650.    -- functions, no procedure) are automatically detected by the 
  651.    -- compiler. The C runtime is defined in files basic_"directory.h" and 
  652.    -- "basic_directory.c" of "SmallEiffel/sys/runtime/". The Java runtime 
  653.    -- is not yet implemented. In the futur, this will be done in file 
  654.    -- "SmallEiffel/sys/runtime/SmallEiffelRuntime.java".
  655.    --
  656.  
  657.    basic_directory_open(path_pointer: POINTER): POINTER is
  658.          -- Try to open some existing directory using `path'. When `Result'
  659.          -- `is_not_null', the directory is correctly opened and `Result' is
  660.          -- a valid handle for this directory. Using `Result', one can 
  661.          -- then scan the content of the directory using function 
  662.          -- `basic_directory_read_entry' and `basic_directory_get_entry_name'. Finally, 
  663.          -- a `is_not_null' directory must be closed using function
  664.          -- `basic_directory_close'.
  665.       require
  666.          path_pointer.is_not_null
  667.       external "SmallEiffel"
  668.       end;
  669.  
  670.    basic_directory_read_entry(dirstream: POINTER): POINTER is
  671.          -- Read an return a new entry using the directory handle `dirstream'
  672.          -- obtained with function `basic_directory_open'. When there is no more 
  673.          -- entry, the `Result' becomes `is_null'.
  674.       require
  675.          dirstream.is_not_null
  676.       external "SmallEiffel"
  677.       end;
  678.  
  679.    basic_directory_get_entry_name(entry: POINTER): POINTER is
  680.          -- Read an return a new entry using the directory handle `dirstream'
  681.          -- obtained with function `basic_directory_open'.
  682.          -- When there is no more entry, the `Result' becomes `is_null'.
  683.       require
  684.          entry.is_not_null
  685.       external "SmallEiffel"
  686.       end;
  687.  
  688.    basic_directory_close(dirstream: POINTER): BOOLEAN is
  689.          -- Try to close some opened `dirstream' directory.
  690.          -- A true result indicates that the directory is correctly
  691.          -- closed.
  692.       require
  693.          dirstream.is_not_null
  694.       external "SmallEiffel"
  695.       end;
  696.  
  697.    basic_directory_current_working_directory: POINTER is
  698.          -- Try to get the current working directory path.
  699.       external "SmallEiffel"
  700.       end;
  701.  
  702.    basic_directory_chdir(destination: POINTER): BOOLEAN is
  703.          -- Try to change the current working directory using `destination'.
  704.       external "SmallEiffel"
  705.       end;
  706.  
  707.    basic_directory_mkdir(directory_path: POINTER): BOOLEAN is
  708.          -- Try to create a new directory using `directory_path'.
  709.       external "SmallEiffel"
  710.       end;
  711.  
  712.    basic_directory_rmdir(directory_path: POINTER): BOOLEAN is
  713.          -- Try to remove `directory_path'.
  714.       external "SmallEiffel"
  715.       end;
  716.  
  717. end -- BASIC_DIRECTORY
  718.